              package com.java.diagnostics.visualizer.postprocessor.vgc.analysis;
              
              import com.java.diagnostics.visualizer.data.AggregateData;
              import com.java.diagnostics.visualizer.data.DataPoint;
              import com.java.diagnostics.visualizer.data.DataSet;
              import com.java.diagnostics.visualizer.data.TupleData;
              import com.java.diagnostics.visualizer.data.TupleDataBuilder;
              import com.java.diagnostics.visualizer.data.Variant;
              import com.java.diagnostics.visualizer.data.axes.AxisPair;
              import com.java.diagnostics.visualizer.data.axes.DataAxis;
              import com.java.diagnostics.visualizer.data.axes.XDataAxis;
              import com.java.diagnostics.visualizer.data.axes.YDataAxis;
              import com.java.diagnostics.visualizer.exceptions.GCAndMemoryVisualizerException;
              import com.java.diagnostics.visualizer.factory.DataFactory;
              import com.java.diagnostics.visualizer.gc.defaultextensions.util.Messages;
              import com.java.diagnostics.visualizer.impl.factory.LogFactory;
              import com.java.diagnostics.visualizer.metadata.TupleMetaData;
              import com.java.diagnostics.visualizer.metadata.TupleMetaData.TableField;
              import com.java.diagnostics.visualizer.metadata.TupleMetaData.TableType;
              import com.java.diagnostics.visualizer.parser.vgc.InstanceVGCParser;
              import com.java.diagnostics.visualizer.parser.vgc.constants.VGCAxes;
              import com.java.diagnostics.visualizer.parser.vgc.constants.VGCGCScopes;
              import com.java.diagnostics.visualizer.parser.vgc.converters.NonLinearHeapPercentConverter;
              import com.java.diagnostics.visualizer.postprocessing.PostProcessor;
              import com.java.diagnostics.visualizer.properties.OutputProperties;
              import java.util.logging.Logger;
              
              public class DerivedVGCDataPostProcessor
                implements PostProcessor
              {
                private static final String ADD_SUMMARY_DATA_METHOD = "addSummaryData";
                public static final String SCAVENGE = "scavenge";
                private static final String CALCULATED_DATA = Messages.getString("DerivedVGCDataPostProcessor.calculated.data.comment");
              
                private static final Logger TRACE = LogFactory.getTrace(DerivedVGCDataPostProcessor.class);
              
                private DataFactory hiddenFactory = DataFactory.getFactory(DataFactory.HIDDEN);
              
                private final String className = getClass().getName();
              
                private static final DataFactory heapFactory = InstanceVGCParser.heapFactory;
              
                public void postprocess(DataSet dataSet, OutputProperties properties)
                {
                  TRACE.entering(this.className, "postprocess");
                  addSummaryData(dataSet, properties);
              
                  Variant[] variants = dataSet.getVariants();
              
                  for (int i = 0; i < variants.length; i++)
                  {
                    addSummaryData(variants[i], properties);
                  }
              
                  TRACE.exiting(this.className, "postprocess");
                }
              
                private void addSummaryData(AggregateData data, OutputProperties properties)
                {
                  TRACE.entering(this.className, "addSummaryData");
              
                  addNewTupleData(data, properties);
                  TRACE.exiting(this.className, "addSummaryData");
                }
              
                private void addNewTupleData(AggregateData data, OutputProperties properties)
                {
                  try
                  {
                    calculateOccupancies(data, properties);
                    calculateUnusableHeap(data);
                    calculateFreeOrUsedBeforeAndAfterGC(data);
                    calculateUsedHeapAfterGlobalGCs(data);
                    calculateUsedSOALOA(data);
                    calculateUsedTenuredAndNursery(data);
                    calculateAmountFreed(data);
                    calculateRateOfGC(data);
                    calculateTenureRate(data);
                    calculateFragmentation(data, properties);
                    calculateNumaStartTotal(data);
                    calculateNumaEndTotal(data);
                    calculateUsedTenuredHeapAfterGlobalGCs(data);
                  } catch (GCAndMemoryVisualizerException e) {
                    TRACE.warning(e.toString());
                  }
                }
              
                private void calculateRateOfGC(AggregateData data) {
                  TupleData amountFreed = data.getTupleData("VGCLabels.amount.freed");
                  TupleData intervals = data.getTupleData("VGCLabels.gc.intervals");
              
                  if ((amountFreed != null) && (intervals != null)) {
                    DataPoint[] freedPoints = amountFreed.getDataPoints();
                    DataPoint[] intervalPoints = intervals.getDataPoints();
              
                    AxisPair axisPair = amountFreed.getAxisPair();
                    TupleDataBuilder gcRate = heapFactory.createTupleData(
                      "VGCLabels.gc.rate", Messages.getString("VGCLabels.gc.rate"), 
                      axisPair);
              
                    TupleMetaData metaData = new TupleMetaData(TupleMetaData.TableType.ARITHMETIC, 
                      new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
              
                    gcRate.setTupleMetaData(metaData);
              
                    for (int i = 0; i < freedPoints.length; i++) {
                      double interval = intervalPoints[i].getRawY();
              
                      if (interval > 0.0D) {
                        double rate = freedPoints[i].getRawY() / interval;
              
                        gcRate.addDataPoint(freedPoints[i].getSequenceUID(), 
                          freedPoints[i].getRawX(), rate, CALCULATED_DATA);
                      }
                    }
                    data.add(gcRate);
                  }
                }
              
                private void calculateTenureRate(AggregateData data) {
                  TupleData amountTenured = data.getTupleData("VGCLabels.amount.tenured");
                  TupleData intervals = data.getTupleData("VGCLabels.gc.intervals");
              
                  if ((amountTenured != null) && (intervals != null)) {
                    DataPoint[] freedPoints = amountTenured.getDataPoints();
                    DataPoint[] intervalPoints = intervals.getDataPoints();
              
                    AxisPair axisPair = amountTenured.getAxisPair();
                    TupleDataBuilder tenureRate = heapFactory.createTupleData(
                      "VGCLabels.tenure.rate", 
                      Messages.getString("VGCLabels.tenure.rate"), axisPair);
              
                    TupleMetaData metaData = new TupleMetaData(TupleMetaData.TableType.ARITHMETIC, 
                      new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
              
                    tenureRate.setTupleMetaData(metaData);
              
                    for (int i = 0; i < freedPoints.length; i++) {
                      double interval = intervalPoints[i].getRawY();
              
                      if (interval > 0.0D)
                      {
                        double rate = freedPoints[i].getRawY() / interval;
              
                        tenureRate.addDataPoint(freedPoints[i].getSequenceUID(), 
                          freedPoints[i].getRawX(), rate, CALCULATED_DATA);
                      }
                    }
                    data.add(tenureRate);
                  }
                }
              
                private void calculateFreeOrUsedBeforeAndAfterGC(AggregateData data)
                {
                  String freeHeapBeforeLabel = "VGCLabels.free.flat.heap.before.gc";
                  String usedHeapBeforeLabel = "VGCLabels.live.normal.heap.before.gc";
                  String totalHeapBeforeLabel = "VGCLabels.total.flat.heap.before.gc";
                  String freeHeapAfterLabel = "VGCLabels.free.flat.heap";
                  String usedHeapAfterLabel = "VGCLabels.live.normal.heap.after.gc";
                  String totalHeapAfterLabel = "VGCLabels.flat.heap.size";
              
                  calculateMissingDifferenceTuple(data, usedHeapBeforeLabel, 
                    totalHeapBeforeLabel, freeHeapBeforeLabel);
              
                  calculateMissingDifferenceTuple(data, freeHeapAfterLabel, 
                    totalHeapAfterLabel, usedHeapAfterLabel);
                  calculateMissingDifferenceTuple(data, usedHeapAfterLabel, 
                    totalHeapAfterLabel, freeHeapAfterLabel);
                }
              
                private void calculateUsedHeapAfterGlobalGCs(AggregateData data)
                {
                  int globalGCScope = VGCGCScopes.nameToInt("global");
                  TupleData amountFree = data
                    .getTupleData("VGCLabels.live.normal.heap.after.gc");
                  TupleData gcScopes = data.getTupleData("VGCLabels.gc.scopes");
              
                  if ((amountFree != null) && (gcScopes != null)) {
                    TupleDataBuilder amountFreeAfterGlobal = heapFactory
                      .createTupleData(
                      "VGCLabels.live.heap.after.global.gc", 
                      Messages.getString("VGCLabels.live.heap.after.global.gc"), 
                      amountFree.getAxisPair());
              
                    TupleMetaData amountFreeAfterGlobalMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    amountFreeAfterGlobal
                      .setTupleMetaData(amountFreeAfterGlobalMetaData);
              
                    boolean added = false;
                    for (DataPoint dataPoint : gcScopes.getDataPoints()) {
                      if ((dataPoint.getRawY() == globalGCScope) && 
                        (amountFree.getDataPoint(dataPoint.getSequenceUID()) != null)) {
                        DataPoint globalPoint = amountFree
                          .getDataPoint(dataPoint.getSequenceUID());
                        amountFreeAfterGlobal.addDataPoint(globalPoint);
                        added = true;
                      }
              
                    }
              
                    if (added)
                      data.add(amountFreeAfterGlobal);
                  }
                }
              
                private void calculateUsedTenuredHeapAfterGlobalGCs(AggregateData data)
                {
                  if (data == null) {
                    return;
                  }
                  int globalGCScope = VGCGCScopes.nameToInt("global");
                  TupleData amountFree = data
                    .getTupleData("VGCLabels.live.tenured.heap.after.gc");
                  TupleData gcScopes = data.getTupleData("VGCLabels.gc.scopes");
              
                  if ((amountFree != null) && (gcScopes != null)) {
                    TupleDataBuilder amountFreeAfterGlobal = heapFactory
                      .createTupleData(
                      "VGCLabels.live.tenured.heap.after.global.gc", 
                      Messages.getString("VGCLabels.live.tenured.heap.after.global.gc"), 
                      amountFree.getAxisPair());
              
                    TupleMetaData amountFreeAfterGlobalMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    amountFreeAfterGlobal
                      .setTupleMetaData(amountFreeAfterGlobalMetaData);
              
                    boolean added = false;
                    for (DataPoint dataPoint : gcScopes.getDataPoints()) {
                      if ((dataPoint.getRawY() == globalGCScope) && 
                        (amountFree.getDataPoint(dataPoint.getSequenceUID()) != null)) {
                        DataPoint globalPoint = amountFree
                          .getDataPoint(dataPoint.getSequenceUID());
                        amountFreeAfterGlobal.addDataPoint(globalPoint);
              
                        added = true;
                      }
              
                    }
              
                    if (added)
                      data.add(amountFreeAfterGlobal);
                  }
                }
              
                private void calculateOccupancies(AggregateData data, OutputProperties properties)
                  throws GCAndMemoryVisualizerException
                {
                  TupleData total = data.getTupleData("VGCLabels.flat.heap.size");
                  TupleData free = data.getTupleData("VGCLabels.free.flat.heap");
              
                  DataPoint[] frees = (DataPoint[])null;
                  YDataAxis totalYAxis = VGCAxes.prepareHeapAxis(properties);
              
                  AxisPair totalOccupancyAxisPair = null;
                  if ((total != null) && (free != null)) {
                    frees = free.getDataPoints();
                    totalOccupancyAxisPair = InstanceVGCParser.heapFactory
                      .createAxisPair(total.getXAxis(), totalYAxis);
                  }
                  else {
                    TupleData tenuredTotal = data.getTupleData("VGCLabels.tenured.heap.size");
                    TupleData nurseryTotal = data.getTupleData("VGCLabels.nursery.size");
              
                    TupleData tenuredFree = data
                      .getTupleData("VGCLabels.free.tenured.heap");
                    TupleData nurseryFree = data
                      .getTupleData("VGCLabels.free.nursery.heap");
                    if ((tenuredTotal != null) && (tenuredFree != null) && 
                      (nurseryTotal != null) && (nurseryFree != null)) {
                      totalOccupancyAxisPair = InstanceVGCParser.heapFactory
                        .createAxisPair(tenuredTotal.getXAxis(), totalYAxis);
              
                      DataPoint[] tenuredTotals = tenuredTotal.getDataPoints();
                      DataPoint[] tenuredFrees = tenuredFree.getDataPoints();
              
                      if (tenuredTotals.length == tenuredFrees.length)
                      {
                        DataPoint[] nurseryTotals = nurseryTotal.getDataPoints();
                        DataPoint[] nurseryFrees = nurseryFree.getDataPoints();
                        if (nurseryTotals.length == tenuredFrees.length) {
                          TupleDataBuilder freeTuple = InstanceVGCParser.heapFactory
                            .createTupleData(
                            "VGCLabels.free.flat.heap", 
                            Messages.getString("VGCLabels.free.flat.heap"), 
                            totalOccupancyAxisPair);
              
                          TupleDataBuilder totalsTuple = InstanceVGCParser.heapFactory
                            .createTupleData(
                            "VGCLabels.flat.heap.size", 
                            Messages.getString("VGCLabels.flat.heap.size"), 
                            totalOccupancyAxisPair);
              
                          TupleMetaData freeMetaData = new TupleMetaData(
                            TupleMetaData.TableType.ARITHMETIC, 
                            new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                          TupleMetaData totalsMetaData = new TupleMetaData(
                            TupleMetaData.TableType.ARITHMETIC, 
                            new TupleMetaData.TableField[] { TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                          freeTuple.setTupleMetaData(freeMetaData);
                          totalsTuple.setTupleMetaData(totalsMetaData);
              
                          for (int i = 0; i < tenuredTotals.length; i++)
                          {
                            int sequence = nurseryFrees[i].getSequenceUID();
                            double x = nurseryFrees[i].getRawX();
              
                            double y = nurseryFrees[i].getRawY() + 
                              tenuredFrees[i].getRawY();
              
                            String comment = tenuredFrees[i].getComment();
              
                            freeTuple.addDataPoint(sequence, x, y, comment);
              
                            y = nurseryTotals[i].getRawY() + 
                              tenuredTotals[i].getRawY();
              
                            totalsTuple.addDataPoint(sequence, x, y, comment);
                          }
              
                          calculateFreeBefores(data, totalOccupancyAxisPair);
                          calculateFreeAfterAlls(data, totalOccupancyAxisPair);
              
                          data.add(totalsTuple);
              
                          data.add(freeTuple);
                        }
              
                      }
              
                    }
              
                  }
              
                  if ((total != null) && (!total.isEmpty()) && (frees != null)) {
                    TupleDataBuilder occupancyTuple = InstanceVGCParser.heapFactory
                      .createTupleData(
                      "VGCLabels.live.normal.heap.after.gc", 
                      Messages.getString("VGCLabels.live.normal.heap.after.gc"), 
                      totalOccupancyAxisPair);
                    TupleMetaData occupancyMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    occupancyTuple.setTupleMetaData(occupancyMetaData);
              
                    calculateOccupanciesForSpecificUnitAwareDataPoints(occupancyTuple, 
                      total, frees, totalOccupancyAxisPair);
              
                    data.add(occupancyTuple);
                  }
                }
              
                private void calculateOccupanciesForSpecificUnitAwareDataPoints(TupleDataBuilder tuple, TupleData total, DataPoint[] frees, AxisPair axes)
                  throws GCAndMemoryVisualizerException
                {
                  DataAxis totalYAxis = axes.getYAxis();
                  DataPoint[] totals = total.getDataPoints();
              
                  NonLinearHeapPercentConverter totalConverter = new NonLinearHeapPercentConverter(
                    total);
              
                  totalYAxis.addUnitConverter(totalConverter);
                  if (frees.length == totals.length)
                    for (int i = 0; i < totals.length; i++) {
                      int sequence = totals[i].getSequenceUID();
                      double x = totals[i].getRawX();
              
                      double y = totals[i].getRawY() - frees[i].getRawY();
                      String comment = totals[i].getComment();
              
                      tuple.addDataPoint(sequence, x, y, comment);
                    }
                }
              
                private void calculateAmountFreed(AggregateData data)
                {
                  TupleData existingAmountFreed = data
                    .getTupleData("VGCLabels.amount.freed");
              
                  if (existingAmountFreed == null)
                  {
                    TupleData freeNurseryHeapBefore = data
                      .getTupleData("VGCLabels.free.nursery.heap.before.gc");
                    TupleData freeNurseryHeapAfter = data
                      .getTupleData("VGCLabels.free.nursery.heap");
              
                    TupleData freeHeapBefore = data
                      .getTupleData("VGCLabels.free.flat.heap.before.gc");
                    TupleData freeHeapAfter = data
                      .getTupleData("VGCLabels.free.flat.heap");
              
                    TupleMetaData newAmountFreedMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX, TupleMetaData.TableField.TOTAL });
              
                    TupleData heapSize = data
                      .getTupleData("VGCLabels.flat.heap.size");
              
                    if ((freeNurseryHeapBefore == null) || 
                      (freeNurseryHeapBefore.isEmpty()))
                    {
                      if ((freeHeapBefore != null) && (freeHeapAfter != null))
                      {
                        DataPoint[] heapBefores = freeHeapBefore.getDataPoints();
                        DataPoint[] heapAfters = freeHeapAfter.getDataPoints();
                        DataPoint[] heapSizes = heapSize.getDataPoints();
              
                        int length = 0;
                        if (heapBefores.length < heapAfters.length)
                          length = heapBefores.length;
                        else {
                          length = heapAfters.length;
                        }
              
                        AxisPair axisPair = freeHeapAfter.getAxisPair();
                        TupleDataBuilder newAmountFreed = heapFactory
                          .createTupleData("VGCLabels.amount.freed", 
                          Messages.getString("VGCLabels.amount.freed"), 
                          axisPair);
              
                        newAmountFreed.setTupleMetaData(newAmountFreedMetaData);
                        for (int i = 0; i < length; i++) {
                          double after = heapAfters[i].getRawY();
                          double before = heapBefores[i].getRawY();
                          double heapChange = 0.0D;
                          if (i > 0) {
                            double heapSizeBefore = heapSizes[(i - 1)].getRawY();
                            double heapSizeAfter = heapSizes[i].getRawY();
                            heapChange = heapSizeBefore - heapSizeAfter;
                          }
              
                          double freed = after - before + heapChange;
              
                          if (freed < 0.0D) {
                            freed = 0.0D;
                          }
                          newAmountFreed.addDataPoint(
                            heapAfters[i].getSequenceUID(), heapAfters[i].getRawX(), 
                            freed, CALCULATED_DATA);
                        }
                        data.add(newAmountFreed);
                      }
                      else
                      {
                        TupleData liveHeapBefore = data
                          .getTupleData("VGCLabels.live.normal.heap.before.gc");
                        TupleData liveHeapAfter = data
                          .getTupleData("VGCLabels.live.normal.heap.after.gc");
              
                        if (liveHeapBefore != null) {
                          DataPoint[] heapBefores = liveHeapBefore
                            .getDataPoints();
                          DataPoint[] heapAfters = liveHeapAfter.getDataPoints();
                          if (heapBefores.length == heapAfters.length) {
                            AxisPair axisPair = liveHeapAfter
                              .getAxisPair();
                            TupleDataBuilder newAmountFreed = heapFactory
                              .createTupleData(
                              "VGCLabels.amount.freed", 
                              Messages.getString("VGCLabels.amount.freed"), 
                              axisPair);
                            newAmountFreed
                              .setTupleMetaData(newAmountFreedMetaData);
              
                            for (int i = 0; i < heapBefores.length; i++) {
                              String comment = heapAfters[i].getComment();
                              double before = heapBefores[i].getRawY();
                              double after = heapAfters[i].getRawY();
              
                              double freed = before - after;
              
                              if (freed < 0.0D) {
                                freed = 0.0D;
                              }
                              newAmountFreed.addDataPoint(
                                heapBefores[i].getSequenceUID(), 
                                heapBefores[i].getRawX(), freed, comment);
                            }
                            data.add(newAmountFreed);
                          }
                        }
                      }
                    } else {
                      TupleData tenured = data
                        .getTupleData("VGCLabels.amount.tenured");
              
                      DataPoint[] heapBefores = freeHeapBefore.getDataPoints();
                      DataPoint[] heapAfters = freeHeapAfter.getDataPoints();
                      DataPoint[] nurseryHeapBefores = freeNurseryHeapBefore
                        .getDataPoints();
                      DataPoint[] nurseryHeapAfters = freeNurseryHeapAfter
                        .getDataPoints();
                      DataPoint[] tenureds = tenured.getDataPoints();
              
                      if (nurseryHeapBefores.length == nurseryHeapAfters.length) {
                        AxisPair axisPair = freeHeapAfter.getAxisPair();
                        TupleDataBuilder newAmountFreed = heapFactory
                          .createTupleData("VGCLabels.amount.freed", 
                          Messages.getString("VGCLabels.amount.freed"), 
                          axisPair);
                        newAmountFreed.setTupleMetaData(newAmountFreedMetaData);
              
                        int tenuredIndex = 0;
                        int scopeValue = -1;
                        TupleData scopes = data
                          .getTupleData("VGCLabels.gc.scopes");
              
                        for (int i = 0; i < nurseryHeapBefores.length; i++) {
                          String comment = nurseryHeapAfters[i].getComment();
              
                          DataPoint scopePoint = scopes
                            .getDataPoint(nurseryHeapAfters[i]
                            .getSequenceUID());
                          if (scopePoint != null)
                            scopeValue = (int)scopePoint.getRawY();
                          double after;
                          double before;
                          //double after;
                          if (scopeValue == VGCGCScopes.GLOBAL_INT) {
                             before = heapBefores[i].getRawY();
                            after = heapAfters[i].getRawY();
                          }
                          else {
                            before = nurseryHeapBefores[i].getRawY();
              
                            after = nurseryHeapAfters[i].getRawY() - 
                              tenureds[tenuredIndex].getRawY();
                            tenuredIndex++;
                          }
              
                          double freed = after - before;
              
                          if (freed < 0.0D) {
                            freed = 0.0D;
                          }
                          newAmountFreed.addDataPoint(
                            nurseryHeapBefores[i].getSequenceUID(), 
                            nurseryHeapBefores[i].getRawX(), freed, comment);
                        }
                        data.add(newAmountFreed);
                      }
                    }
                  }
                }
              
                private void calculateFreeBefores(AggregateData data, AxisPair axisPair) {
                  TupleData tenuredFreeBefore = data
                    .getTupleData("VGCLabels.free.tenured.heap.before.gc");
                  TupleData nurseryFreeBefore = data
                    .getTupleData("VGCLabels.free.nursery.heap.before.gc");
              
                  if (tenuredFreeBefore != null) {
                    DataPoint[] tenuredFreeBefores = tenuredFreeBefore.getDataPoints();
                    DataPoint[] nurseryFreeBefores = nurseryFreeBefore.getDataPoints();
              
                    TupleDataBuilder freeBeforeTuple = InstanceVGCParser.heapFactory
                      .createTupleData(
                      "VGCLabels.free.flat.heap.before.gc", 
                      Messages.getString("VGCLabels.free.flat.heap.before.gc"), 
                      axisPair);
              
                    TupleMetaData freeBeforeMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    freeBeforeTuple.setTupleMetaData(freeBeforeMetaData);
              
                    for (int i = 0; i < tenuredFreeBefores.length; i++) {
                      double free = tenuredFreeBefores[i].getRawY() + 
                        nurseryFreeBefores[i].getRawY();
                      freeBeforeTuple.addDataPoint(
                        tenuredFreeBefores[i].getSequenceUID(), tenuredFreeBefores[i].getRawX(), 
                        free, CALCULATED_DATA);
                    }
                    data.add(freeBeforeTuple);
                  }
                }
              
                private void calculateFreeAfterAlls(AggregateData data, AxisPair axisPair) {
                  TupleData tenuredFreeAfterAll = data
                    .getTupleData("VGCLabels.free.tenured.heap.after.all.gcs");
                  TupleData nurseryFreeAfterAll = data
                    .getTupleData("VGCLabels.free.nursery.heap.after.all.gcs");
              
                  if (tenuredFreeAfterAll != null) {
                    DataPoint[] tenuredFreeAfterAlls = tenuredFreeAfterAll
                      .getDataPoints();
                    DataPoint[] nurseryFreeAfterAlls = nurseryFreeAfterAll
                      .getDataPoints();
              
                    TupleDataBuilder freeAfterAllTuple = this.hiddenFactory.createTupleData(
                      "VGCLabels.free.flat.heap.after.all.gcs", 
                      Messages.getString("VGCLabels.free.flat.heap.before.gc"), 
                      axisPair);
                    TupleMetaData freeAfterAllMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    freeAfterAllTuple.setTupleMetaData(freeAfterAllMetaData);
                    for (int i = 0; i < tenuredFreeAfterAlls.length; i++) {
                      double free = tenuredFreeAfterAlls[i].getRawY() + 
                        nurseryFreeAfterAlls[i].getRawY();
                      freeAfterAllTuple.addDataPoint(
                        tenuredFreeAfterAlls[i].getSequenceUID(), tenuredFreeAfterAlls[i].getRawX(), 
                        free, CALCULATED_DATA);
                    }
                    data.add(freeAfterAllTuple);
                  }
                }
              
                private void calculateNumaStartTotal(AggregateData data) {
                  TupleData commonNuma = data.getTupleData("VGCLabels.common.numa.start");
              
                  if (commonNuma != null) {
                    TupleData localNuma = data.getTupleData("VGCLabels.local.numa.start");
                    TupleData nonLocalNuma = data
                      .getTupleData("VGCLabels.non.local.numa.start");
                    DataPoint[] commonNumaPoints = commonNuma.getDataPoints();
                    DataPoint[] localNumaPoints = localNuma.getDataPoints();
                    DataPoint[] nonLocalNumaPoints = nonLocalNuma.getDataPoints();
              
                    TupleDataBuilder totalNumaTuple = heapFactory.createTupleData(
                      "VGCLabels.total.numa.start", 
                      Messages.getString("VGCLabels.total.numa.start"), 
                      commonNuma.getAxisPair());
                    TupleMetaData totalNumaMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    totalNumaTuple.setTupleMetaData(totalNumaMetaData);
              
                    for (int i = 0; i < commonNumaPoints.length; i++) {
                      double total = commonNumaPoints[i].getRawY() + 
                        localNumaPoints[i].getRawY() + 
                        nonLocalNumaPoints[i].getRawY();
                      totalNumaTuple.addDataPoint(
                        commonNumaPoints[i].getSequenceUID(), commonNumaPoints[i].getRawX(), 
                        total, CALCULATED_DATA);
                    }
                    data.add(totalNumaTuple);
                  }
                }
              
                private void calculateNumaEndTotal(AggregateData data) {
                  TupleData commonNuma = data.getTupleData("VGCLabels.common.numa.end");
              
                  if (commonNuma != null) {
                    TupleData localNuma = data.getTupleData("VGCLabels.local.numa.end");
                    TupleData nonLocalNuma = data
                      .getTupleData("VGCLabels.non.local.numa.end");
                    DataPoint[] commonNumaPoints = commonNuma.getDataPoints();
                    DataPoint[] localNumaPoints = localNuma.getDataPoints();
                    DataPoint[] nonLocalNumaPoints = nonLocalNuma.getDataPoints();
              
                    TupleDataBuilder totalNumaTuple = heapFactory.createTupleData(
                      "VGCLabels.total.numa.end", 
                      Messages.getString("VGCLabels.total.numa.end"), 
                      commonNuma.getAxisPair());
                    TupleMetaData totalNumaMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    totalNumaTuple.setTupleMetaData(totalNumaMetaData);
              
                    for (int i = 0; i < commonNumaPoints.length; i++) {
                      double total = commonNumaPoints[i].getRawY() + 
                        localNumaPoints[i].getRawY() + 
                        nonLocalNumaPoints[i].getRawY();
                      totalNumaTuple.addDataPoint(
                        commonNumaPoints[i].getSequenceUID(), commonNumaPoints[i].getRawX(), 
                        total, CALCULATED_DATA);
                    }
                    data.add(totalNumaTuple);
                  }
                }
              
                private void calculateFragmentation(AggregateData data, OutputProperties properties)
                {
                  TupleData amountFreed = data.getTupleData("VGCLabels.amount.freed");
              
                  TupleData unusableHeap = data.getTupleData("VGCLabels.unusable.heap");
              
                  TupleData objectSize = data
                    .getTupleData("VGCLabels.request.sizes.which.triggered.failures");
              
                  if ((amountFreed != null) && (unusableHeap != null) && (objectSize != null)) {
                    DataPoint[] unusablePoints = unusableHeap.getDataPoints();
                    XDataAxis xAxis = amountFreed.getXAxis();
                    AxisPair axisPair = heapFactory.createAxisPair(xAxis, 
                      VGCAxes.prepareNumberAxis(properties));
              
                    TupleDataBuilder fragmentation = InstanceVGCParser.heapFactory
                      .createTupleData("VGCLabels.fragmentation", 
                      Messages.getString("VGCLabels.fragmentation"), axisPair);
                    TupleMetaData fragmentationMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    fragmentation.setTupleMetaData(fragmentationMetaData);
                    int fragmentationPointCount = 0;
              
                    for (int i = 0; i < unusablePoints.length; i++)
                    {
                      String originalComment = unusablePoints[i].getComment();
              
                      if ((originalComment.indexOf("scavenge") == -1) && 
                        (originalComment.indexOf("sys") == -1))
                      {
                        if (originalComment.indexOf("con") == -1)
                        {
                          DataPoint dataPoint = unusablePoints[i];
                          int sequence = dataPoint.getSequenceUID();
              
                          DataPoint requestedPoint = objectSize
                            .getDataPoint(sequence);
                          if (requestedPoint != null) {
                            double requested = requestedPoint.getRawY();
                            double x = dataPoint.getRawX();
                            double y = dataPoint.getRawY() / requested;
              
                            String comment = dataPoint.getComment() + 
                              dataPoint.getRawY() + "," + 
                              requested;
                            fragmentation.addDataPoint(sequence, x, y, 
                              comment);
                            fragmentationPointCount++;
                          }
                        }
                      }
              
                    }
              
                    if (fragmentationPointCount > 0)
                      data.add(fragmentation);
                  }
                }
              
                private void calculateUnusableHeap(AggregateData data)
                {
                  TupleData unusedHeap = null;
              
                  TupleData freeHeapBefore = data
                    .getTupleData("VGCLabels.free.tenured.heap.before.gc");
                  boolean isGencon = true;
                  if ((freeHeapBefore == null) || (freeHeapBefore.isEmpty()))
                  {
                    freeHeapBefore = data.getTupleData("VGCLabels.free.soa.before.collection");
                    if (freeHeapBefore == null) {
                      freeHeapBefore = data
                        .getTupleData("VGCLabels.free.flat.heap.before.gc");
                    }
                    isGencon = false;
                  }
              
                  TupleData flatSize = data.getTupleData("VGCLabels.flat.heap.size");
                  int flatLength = 0;
                  if (flatSize != null) {
                    flatLength = flatSize.length();
                  }
              
                  boolean validSOA = (freeHeapBefore != null) && 
                    (freeHeapBefore.length() > flatLength * 0.9D);
              
                  if (validSOA) {
                    AxisPair flatHeapAxisPair = data.getTupleData(
                      "VGCLabels.free.flat.heap").getAxisPair();
                    unusedHeap = doUnusableHeapFromSOA(freeHeapBefore, 
                      flatHeapAxisPair, isGencon);
                  } else if ((freeHeapBefore != null) && (!freeHeapBefore.isEmpty())) {
                    unusedHeap = mashTogetherSOAAndFlatHeapForUnusableHeap(data, 
                      isGencon);
                  }
              
                  if ((unusedHeap != null) && (!unusedHeap.isEmpty()))
                    data.add(unusedHeap);
                }
              
                private TupleData mashTogetherSOAAndFlatHeapForUnusableHeap(AggregateData data, boolean isGencon)
                {
                  TupleDataBuilder unusedHeap = null;
              
                  TupleData soaBefore = data.getTupleData("VGCLabels.free.soa.before.collection");
                  TupleData flatBefore = data
                    .getTupleData("VGCLabels.free.flat.heap.before.gc");
              
                  if (!isGencon)
                  {
                    if ((soaBefore != null) && (flatBefore != null))
                    {
                      DataPoint[] soaPoints = soaBefore.getDataPoints();
                      DataPoint[] flatPoints = flatBefore.getDataPoints();
                      AxisPair axisPair = flatBefore.getAxisPair();
                      String unusedLabel = "VGCLabels.unusable.heap";
                      unusedHeap = InstanceVGCParser.heapFactory.createTupleData(
                        unusedLabel, Messages.getString(unusedLabel), axisPair);
                      TupleMetaData unusedHeapMetaData = new TupleMetaData(
                        TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                        TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                      unusedHeap.setTupleMetaData(unusedHeapMetaData);
                      int soaIndex = 0;
              
                      for (int i = 0; i < flatPoints.length; i++)
                      {
                        String originalComment = flatPoints[i].getComment();
              
                        if ((originalComment.indexOf("scavenge") == -1) && 
                          (originalComment.indexOf("sys") == -1))
                        {
                          if (originalComment.indexOf("con") == -1)
                          {
                            do
                            {
                              soaIndex++;
              
                              if (soaPoints[soaIndex].getRawX() >= 
                                flatPoints[i].getRawX()) break; 
                            }while (soaIndex < soaPoints.length - 1);
              
                            while ((soaPoints[soaIndex].getRawX() > 
                              flatPoints[i].getRawX()) && 
                              (soaIndex > 0))
                              soaIndex--;
                            double y;
                            //double y;
                            if (soaPoints[soaIndex].getRawX() == 
                              flatPoints[i].getRawX())
                              y = soaPoints[soaIndex].getRawY();
                            else {
                              y = flatPoints[i].getRawY();
                            }
              
                            int sequence = flatPoints[i].getSequenceUID();
                            double x = flatPoints[i].getRawX();
              
                            unusedHeap.addDataPoint(sequence, x, y, 
                              originalComment);
                          }
              
                        }
              
                      }
              
                    }
              
                  }
              
                  return unusedHeap;
                }
              
                private TupleData doUnusableHeapFromSOA(TupleData freeHeapBefore, AxisPair flatHeapAxisPair, boolean isGencon)
                {
                  TupleDataBuilder unusedHeap = null;
                  if (isGencon) {
                    return unusedHeap;
                  }
              
                  TupleData soaBefore = freeHeapBefore;
              
                  if (soaBefore != null)
                  {
                    DataPoint[] soaPoints = soaBefore.getDataPoints();
                    String unusedLabel = "VGCLabels.unusable.heap";
                    unusedHeap = InstanceVGCParser.heapFactory.createTupleData(
                      unusedLabel, Messages.getString(unusedLabel), 
                      flatHeapAxisPair);
                    TupleMetaData unusedHeapMetaData = new TupleMetaData(
                      TupleMetaData.TableType.ARITHMETIC, new TupleMetaData.TableField[] { 
                      TupleMetaData.TableField.MEAN, TupleMetaData.TableField.MIN, TupleMetaData.TableField.MAX });
                    unusedHeap.setTupleMetaData(unusedHeapMetaData);
              
                    for (int i = 0; i < soaPoints.length; i++)
                    {
                      String originalComment = soaPoints[i].getComment();
              
                      if ((originalComment.indexOf("scavenge") == -1) && 
                        (originalComment.indexOf("sys") == -1))
                      {
                        if (originalComment.indexOf("con") == -1)
                        {
                          DataPoint dataPoint = soaPoints[i];
              
                          unusedHeap.addDataPoint(dataPoint.getSequenceUID(), 
                            dataPoint.getRawX(), dataPoint.getRawY(), 
                            dataPoint.getComment());
                        }
              
                      }
              
                    }
              
                  }
              
                  return unusedHeap;
                }
              
                private void calculateUsedSOALOA(AggregateData data) {
                  try {
                    calculateMissingDifferenceTuple(data, "VGCLabels.free.soa.before.collection", 
                      "VGCLabels.total.soa.before", "VGCLabels.used.soa.before.collection");
                    calculateMissingDifferenceTuple(data, "VGCLabels.free.loa.before.collection", 
                      "VGCLabels.total.loa.before", "VGCLabels.used.loa.before.collection");
                    calculateMissingDifferenceTuple(data, "VGCLabels.free.soa.after.collection", 
                      "VGCLabels.total.soa.after", "VGCLabels.used.soa.after.collection");
                    calculateMissingDifferenceTuple(data, "VGCLabels.free.loa.after.collection", 
                      "VGCLabels.total.loa.after", "VGCLabels.used.loa.after.collection");
                  } catch (Throwable t) {
                    TRACE.warning(t.toString());
                  }
                }
              
                private void calculateUsedTenuredAndNursery(AggregateData data)
                {
                  try {
                    calculateMissingDifferenceTuple(data, 
                      "VGCLabels.free.nursery.heap", 
                      "VGCLabels.nursery.size", 
                      "VGCLabels.live.nursery.heap.after.gc");
                    calculateMissingDifferenceTuple(data, 
                      "VGCLabels.free.tenured.heap", 
                      "VGCLabels.tenured.heap.size", 
                      "VGCLabels.live.tenured.heap.after.gc");
                  } catch (Throwable t) {
                    TRACE.warning(t.toString());
                  }
                }
              
                private void calculateMissingDifferenceTuple(AggregateData data, String knownTupleLabel, String totalTupleLabel, String differenceTupleLabel)
                {
                  TupleData knownTuple = data.getTupleData(knownTupleLabel);
                  TupleData totalTuple = data.getTupleData(totalTupleLabel);
              
                  if ((data.getTupleData(differenceTupleLabel) == null) && 
                    (totalTuple != null) && (!totalTuple.isEmpty()) && 
                    (knownTuple != null) && (!knownTuple.isEmpty())) {
                    TupleDataBuilder differenceTuple = heapFactory.createTupleData(
                      differenceTupleLabel, 
                      Messages.getString(differenceTupleLabel), 
                      knownTuple.getXAxis(), knownTuple.getYAxis());
                    differenceTuple.setTupleMetaData(knownTuple.getTupleMetaData());
                    DataPoint[] knownPoints = knownTuple.getDataPoints();
                    DataPoint[] totalPoints = totalTuple.getDataPoints();
                    if (knownPoints.length != totalPoints.length) {
                      return;
                    }
                    for (int i = 0; i < knownPoints.length; i++) {
                      double difference = totalPoints[i].getRawY() - 
                        knownPoints[i].getRawY();
                      differenceTuple.addDataPoint(knownPoints[i].getSequenceUID(), 
                        knownPoints[i].getRawX(), difference, CALCULATED_DATA);
                    }
                    data.add(differenceTuple);
                  }
                }
              }

